#include <sxPlotAxes.h>

const static unsigned int DEFAULT_TICKS = 5;
const static float DEFAULT_TICK_SPACING = 1.0f;
const static unsigned int DEFAULT_TICK_INTERVAL = 5;
const static float DEFAULT_FIXED_LENGTH = 10.0f;

Sx::Graphics::Objects::PlotAxes::PlotAxes() : GraphicsObject() {
	this->initalize();
}

Sx::Graphics::Objects::PlotAxes::PlotAxes(const PlotAxes& plot) : GraphicsObject() {
	this->nxTicks = plot.nxTicks;
	this->pxTicks = plot.pxTicks;
	this->nyTicks = plot.nyTicks;
	this->pyTicks = plot.pyTicks;
	this->nzTicks = plot.nzTicks;
	this->pzTicks = plot.pzTicks;
	this->min = plot.min;
	this->max = plot.max;
	this->tickSpacing = plot.tickSpacing;
	this->displayX = plot.displayX;
	this->displayY = plot.displayY;
	this->displayZ = plot.displayZ;
	this->displayTickLabels = plot.displayTickLabels;
	this->tickLabelInterval = plot.tickLabelInterval;
	this->displayTicks = plot.displayTicks;
	this->displayGrid_XY = plot.displayGrid_XY;
	this->displayGrid_XZ = plot.displayGrid_XZ;
	this->displayGrid_YZ = plot.displayGrid_YZ;
}

Sx::Graphics::Objects::PlotAxes::PlotAxes(unsigned int tickCount, float tickSpacing) : GraphicsObject() {
	this->initalize();
	this->nxTicks = this->nyTicks = this->nzTicks = tickCount;
	this->tickSpacing = tickSpacing;
}

Sx::Graphics::Objects::PlotAxes::PlotAxes(unsigned int nxTickCount, unsigned int pxTickCount, unsigned int nyTickCount, unsigned int pyTickCount, unsigned int nzTickCount, unsigned int pzTickCount, float tickSpacing) : GraphicsObject() {
	this->initalize();
	this->nxTicks = nxTickCount;
	this->pxTicks = pxTickCount;
	this->nyTicks = nyTickCount;
	this->pyTicks = pyTickCount;
	this->nzTicks = nzTickCount;
	this->pzTicks = pzTickCount;
	this->tickSpacing = tickSpacing;
}

Sx::Graphics::Objects::PlotAxes::PlotAxes(const Eigen::Vector3i& min, const Eigen::Vector3i& max) : GraphicsObject() {
	this->initalize();
	this->min.x() = min.x() * this->tickSpacing;
	this->min.y() = min.y() * this->tickSpacing;
	this->min.z() = min.z() * this->tickSpacing;
	this->max.x() = max.x() * this->tickSpacing;
	this->max.y() = max.y() * this->tickSpacing;
	this->max.z() = max.z() * this->tickSpacing;
	this->nxTicks = min.x();
	this->pxTicks = max.x();
	this->nyTicks = min.y();
	this->pyTicks = max.y();
	this->nzTicks = min.z();
	this->pzTicks = max.z();
}

void Sx::Graphics::Objects::PlotAxes::initalize() {
	this->nxTicks = this->pxTicks = DEFAULT_TICKS;
	this->nyTicks = this->pyTicks = DEFAULT_TICKS;
	this->nzTicks = this->pzTicks = DEFAULT_TICKS;
	this->min.x() = this->min.y() = this->min.z() = -DEFAULT_FIXED_LENGTH;
	this->max.x() = this->max.y() = this->max.z() = DEFAULT_FIXED_LENGTH;
	this->tickSpacing = DEFAULT_TICK_SPACING;
	this->displayX = true;
	this->displayY = true;
	this->displayZ = true;
	this->displayGrid_XY = true;
	this->displayGrid_XZ = true;
	this->displayGrid_YZ = true;
	this->displayTicks = true;
	this->displayTickLabels = true;
	this->tickLabelInterval = DEFAULT_TICK_INTERVAL;
}

Sx::Graphics::Objects::PlotAxes::~PlotAxes() {}

bool Sx::Graphics::Objects::PlotAxes::construct() {
	return true;
}

void Sx::Graphics::Objects::PlotAxes::update(float dt) {
	return;
}

void Sx::Graphics::Objects::PlotAxes::setFixedLengths(const Eigen::Vector3f& min, const Eigen::Vector3f& max) {
	this->min = min;
	this->max = max;
}

void Sx::Graphics::Objects::PlotAxes::setMinimumLengths(const Eigen::Vector3f& min) {
	this->min = min;
}

void Sx::Graphics::Objects::PlotAxes::setMaximumLengths(const Eigen::Vector3f& max) {
	this->max = max;
}

void Sx::Graphics::Objects::PlotAxes::setMinimumX(float x) {
	this->min.x() = x;
}

void Sx::Graphics::Objects::PlotAxes::setMinimumY(float y) {
	this->min.y() = y;
}

void Sx::Graphics::Objects::PlotAxes::setMinimumZ(float z) {
	this->min.z() = z;
}

void Sx::Graphics::Objects::PlotAxes::setMaximumX(float x) {
	this->max.x() = x;
}

void Sx::Graphics::Objects::PlotAxes::setMaximumY(float y) {
	this->max.y() = y;
}

void Sx::Graphics::Objects::PlotAxes::setMaximumZ(float z) {
	this->max.z() = z;
}

void Sx::Graphics::Objects::PlotAxes::setXLength(float length) {
	this->min.x() = -(length / 2.0f);
	this->max.x() = (length / 2.0f);
}

void Sx::Graphics::Objects::PlotAxes::setYLength(float length) {
	this->min.y() = -(length / 2.0f);
	this->max.y() = (length / 2.0f);
}

void Sx::Graphics::Objects::PlotAxes::setZLength(float length) {
	this->min.z() = -(length / 2.0f);
	this->max.z() = (length / 2.0f);
}

void Sx::Graphics::Objects::PlotAxes::setXExtents(unsigned int nxTicks, unsigned int pxTicks, float tickSpacing) {
	this->nxTicks = nxTicks;
	this->pxTicks = pxTicks;
	this->tickSpacing = tickSpacing;
}

void Sx::Graphics::Objects::PlotAxes::setYExtents(unsigned int nyTicks, unsigned int pyTicks, float tickSpacing) {
	this->nyTicks = nyTicks;
	this->pyTicks = pyTicks;
	this->tickSpacing = tickSpacing;
}

void Sx::Graphics::Objects::PlotAxes::setZExtents(unsigned int nzTicks, unsigned int pzTicks, float tickSpacing) {
	this->nzTicks = nzTicks;
	this->pzTicks = pzTicks;
	this->tickSpacing = tickSpacing;
}

void Sx::Graphics::Objects::PlotAxes::setXTicks(unsigned int ticks, bool positive) {
	if ( positive ) this->pxTicks = ticks;
	else this->nxTicks = ticks;
}

void Sx::Graphics::Objects::PlotAxes::setYTicks(unsigned int ticks, bool positive) {
	if ( positive ) this->pyTicks = ticks;
	else this->nyTicks = ticks;
}

void Sx::Graphics::Objects::PlotAxes::setZTicks(unsigned int ticks, bool positive) {
	if ( positive ) this->pzTicks = ticks;
	else this->nzTicks = ticks;
}

void Sx::Graphics::Objects::PlotAxes::setTickSpacing(float spacing) {
	this->tickSpacing = spacing;
}

void Sx::Graphics::Objects::PlotAxes::setTickLabelInterval(unsigned int interval) {
	this->tickLabelInterval = interval;
}

void Sx::Graphics::Objects::PlotAxes::setXTicks(unsigned int ticks) {
	this->nxTicks = ticks;
	this->pxTicks = ticks;
}

void Sx::Graphics::Objects::PlotAxes::setYTicks(unsigned int ticks) {
	this->nyTicks = ticks;
	this->pyTicks = ticks;
}

void Sx::Graphics::Objects::PlotAxes::setZTicks(unsigned int ticks) {
	this->nzTicks = ticks;
	this->pzTicks = ticks;
}

void Sx::Graphics::Objects::PlotAxes::setAxisVisibility(Math::Axis axis, bool b) {
	switch ( axis ) {
	case Math::X: this->displayX = b; break;
	case Math::Y: this->displayY = b; break;
	case Math::Z: this->displayZ = b; break;
	};
}

void Sx::Graphics::Objects::PlotAxes::setAxisXVisible(bool b) {
	this->displayX = b;
}

void Sx::Graphics::Objects::PlotAxes::setAxisYVisible(bool b) {
	this->displayY = b;
}

void Sx::Graphics::Objects::PlotAxes::setAxisZVisible(bool b) {
	this->displayZ = b;
}

void Sx::Graphics::Objects::PlotAxes::hideAxes() {
	this->displayX = false;
	this->displayY = false;
	this->displayZ = false;
}

void Sx::Graphics::Objects::PlotAxes::hideTicks() {
	this->displayTicks = false;
}

void Sx::Graphics::Objects::PlotAxes::hideTickLabels() {
	this->displayTickLabels = false;
}

void Sx::Graphics::Objects::PlotAxes::hideGrid() {
	this->displayGrid_XY = false;
	this->displayGrid_XZ = false;
	this->displayGrid_YZ = false;
}

void Sx::Graphics::Objects::PlotAxes::hideXAxis() {
	this->displayX = false;
}

void Sx::Graphics::Objects::PlotAxes::hideYAxis() {
	this->displayY = false;
}

void Sx::Graphics::Objects::PlotAxes::hideZAxis() {
	this->displayZ = false;
}

void Sx::Graphics::Objects::PlotAxes::showAxes() {
	this->displayX = true;
	this->displayY = true;
	this->displayZ = true;
}

void Sx::Graphics::Objects::PlotAxes::showTicks() {
	this->displayTicks = true;
}

void Sx::Graphics::Objects::PlotAxes::showTickLabels() {
	this->displayTickLabels = true;
}

void Sx::Graphics::Objects::PlotAxes::showGrid() {
	this->displayGrid_XY = true;
	this->displayGrid_XZ = true;
	this->displayGrid_YZ = true;
}

void Sx::Graphics::Objects::PlotAxes::showXAxis() {
	this->displayX = true;
}

void Sx::Graphics::Objects::PlotAxes::showYAxis() {
	this->displayY = true;
}

void Sx::Graphics::Objects::PlotAxes::showZAxis() {
	this->displayZ = true;
}

void Sx::Graphics::Objects::PlotAxes::setDisplayX(bool b) {
	this->displayX = b;
}

void Sx::Graphics::Objects::PlotAxes::setDisplayY(bool b) {
	this->displayY = b;
}

void Sx::Graphics::Objects::PlotAxes::setDisplayZ(bool b) {
	this->displayZ = b;
}

void Sx::Graphics::Objects::PlotAxes::setDisplayTicks(bool b) {
	this->displayTicks = b;
}

void Sx::Graphics::Objects::PlotAxes::setDisplayTickLabels(bool b) {
	this->displayTickLabels = b;
}

void Sx::Graphics::Objects::PlotAxes::setDisplayGrid(bool b) {
	this->displayGrid_XY = b;
	this->displayGrid_XZ = b;
	this->displayGrid_YZ = b;
}

void Sx::Graphics::Objects::PlotAxes::setDisplayGrid(Math::AxisPlane plane, bool b) {
	switch ( plane ) {
	case Math::XY: this->displayGrid_XY = b; break;
	case Math::YZ: this->displayGrid_YZ = b; break;
	case Math::XZ: this->displayGrid_XZ = b; break;
	};
}

unsigned int Sx::Graphics::Objects::PlotAxes::getXTicks(bool positive) const {
	if ( positive ) return this->pxTicks;
	return this->nxTicks;
}

unsigned int Sx::Graphics::Objects::PlotAxes::getYTicks(bool positive) const {
	if ( positive ) return this->pyTicks;
	return this->nyTicks;
}

unsigned int Sx::Graphics::Objects::PlotAxes::getZTicks(bool positive) const {
	if ( positive ) return this->pzTicks;
	return this->nzTicks;
}

Eigen::Vector3f Sx::Graphics::Objects::PlotAxes::getMinimumFixedLengths() const {
	return this->min;
}

Eigen::Vector3f Sx::Graphics::Objects::PlotAxes::getMaximumFixedLengths() const {
	return this->max;
}

float Sx::Graphics::Objects::PlotAxes::getTickSpacing() const {
	return this->tickSpacing;
}

bool Sx::Graphics::Objects::PlotAxes::xAxisVisible() const {
	return this->displayX;
}

bool Sx::Graphics::Objects::PlotAxes::yAxisVisible() const {
	return this->displayY;
}

bool Sx::Graphics::Objects::PlotAxes::zAxisVisible() const {
	return this->displayZ;
}

bool Sx::Graphics::Objects::PlotAxes::gridVisible(Math::AxisPlane plane) const {
	switch ( plane ) {
	case Math::XY: return this->displayGrid_XY;
	case Math::YZ: return this->displayGrid_YZ;
	case Math::XZ: return this->displayGrid_XZ;
	default: return false;
	};
}

bool Sx::Graphics::Objects::PlotAxes::ticksVisible() const {
	return this->displayTicks;
}

bool Sx::Graphics::Objects::PlotAxes::tickLabelsVisible() const {
	return this->displayTickLabels;
}

unsigned int Sx::Graphics::Objects::PlotAxes::getXTotalTicks() const {
	return this->nxTicks + this->pxTicks;
}

unsigned int Sx::Graphics::Objects::PlotAxes::getYTotalTicks() const {
	return this->nyTicks + this->pyTicks;
}

unsigned int Sx::Graphics::Objects::PlotAxes::getZTotalTicks() const {
	return this->nzTicks + this->pzTicks;
}

unsigned int Sx::Graphics::Objects::PlotAxes::getTickLabelInterval() const {
	return this->tickLabelInterval;
}

float Sx::Graphics::Objects::PlotAxes::getXLength(bool positive) const {
	if ( positive ) return this->pxTicks * this->tickSpacing;
	else return this->nxTicks * this->tickSpacing;
}

float Sx::Graphics::Objects::PlotAxes::getYLength(bool positive) const {
	if ( positive ) return this->pyTicks * this->tickSpacing;
	else return this->nyTicks * this->tickSpacing;
}

float Sx::Graphics::Objects::PlotAxes::getZLength(bool positive) const {
	if ( positive ) return this->pzTicks * this->tickSpacing;
	else return this->nzTicks * this->tickSpacing;
}

float Sx::Graphics::Objects::PlotAxes::getXTotalLength() const {
	return std::abs((this->nxTicks + this->pxTicks) * this->tickSpacing);
}

float Sx::Graphics::Objects::PlotAxes::getYTotalLength() const {
	return std::abs((this->nyTicks + this->pyTicks) * this->tickSpacing);
}

float Sx::Graphics::Objects::PlotAxes::getZTotalLength() const {
	return std::abs((this->nzTicks + this->pzTicks) * this->tickSpacing);
}
